package com.gss.armory.persistence;



import java.util.ArrayList;
import java.util.Date;
import java.util.List;

import org.apache.log4j.Logger;
import org.hibernate.Query;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.Transaction;
import org.hibernate.criterion.DetachedCriteria;
import org.hibernate.criterion.Restrictions;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.dao.DataAccessException;
import org.springframework.orm.hibernate3.support.HibernateDaoSupport;
import org.springframework.stereotype.Repository;

import com.gss.armory.domain.BusinessUnitTypeDTO;
import com.gss.armory.domain.CompanyDetailsDTO;
import com.gss.armory.domain.DepartmentDetailsDTO;
import com.gss.armory.domain.DocGeneralDetailsDTO;
import com.gss.armory.domain.DocumentLinkDTO;
import com.gss.armory.domain.DocumentLinkDTO.DocLinkType;
import com.gss.armory.domain.DocumentMetadataValueDTO;
import com.gss.armory.domain.DocumentTrackDetailsDTO;
import com.gss.armory.domain.DocumentWorkflowDetailsDTO;
import com.gss.armory.domain.DocumentWorkflowDetailsDTO.WorkflowEventStatus;
import com.gss.armory.domain.DocumentWorkflowDetailsDTO.WorkflowStatus;
import com.gss.armory.domain.IDocument;
import com.gss.armory.domain.UserActivityGroup;
import com.gss.common.util.ApplicationUtilities;
import com.gss.security.domain.LocationMasterDTO;
import com.gss.security.domain.RoleDetailsDTO;
import com.gss.security.domain.UserDetailsDTO;

@Repository
public class CommonDAO extends HibernateDaoSupport{
	
	private Logger logger = Logger.getLogger(CommonDAO.class);

	@Autowired
	SessionFactory sessionFactory;
	
	@Autowired
	public CommonDAO(SessionFactory sessionFactory){
		super.setSessionFactory(sessionFactory);
		logger.debug("inside common dao");
	}

	
	public List loadAll(Class entityClass){
		logger.debug("inside method(loadAll): for class with name:" + entityClass.getCanonicalName());
		List results;
			try {
				results = getHibernateTemplate().loadAll(entityClass);
				return results;
			} catch (Throwable e) {
				logger.error(e.getMessage(),e);
			}
		return null;
	}

	public void saveDocMetData(Object docGeneralDetailsDTO) throws DataAccessException{
		logger.debug("inside method(saveDocMetData)");
		getSession().save(docGeneralDetailsDTO);
	}

	public void saveDocumentDetails(IDocument dataToBeSaved) throws Exception{
		logger.debug("inside method(saveDocumentDetails):  for class: " + dataToBeSaved.getClass().getCanonicalName());
		if(dataToBeSaved instanceof DocGeneralDetailsDTO){
			if(((DocGeneralDetailsDTO)dataToBeSaved).getDocCompanyId() == null || ((DocGeneralDetailsDTO)dataToBeSaved).getDocCompanyId() == 0 )
				((DocGeneralDetailsDTO)dataToBeSaved).setDocCompanyId(ApplicationUtilities.getCurrentUserCompanyId());
		}
		try{
			getHibernateTemplate().save(dataToBeSaved);
		}
		catch(Exception e){
			logger.debug(e.getMessage(),e);
		}
	}
	public void updateDocDetails(DocGeneralDetailsDTO detailsDTO) throws Exception
	{
		logger.debug("inside method(updateDocDetails)");
		if(detailsDTO.getDocCompanyId() == null || detailsDTO.getDocCompanyId() == 0){
			detailsDTO.setDocCompanyId(ApplicationUtilities.getCurrentUserCompanyId());
		}
		getHibernateTemplate().update(detailsDTO);
	}
	
	public int updateDocumentDetails(Query query) throws Exception{
		logger.debug("inside method (updateDocumentDetails): executing query :" + query.getQueryString());
		int numOfRowsUpdated =  query.executeUpdate();
		logger.debug("number of rows updated: " + numOfRowsUpdated);
		return numOfRowsUpdated;
	}

	public  List<DocumentWorkflowDetailsDTO> getWorkFlowDetails() throws Exception
	{
		logger.debug("inside method(getWorkFlowDetails)");
		DetachedCriteria criteria = DetachedCriteria.forClass(DocumentWorkflowDetailsDTO.class);
		criteria.add(Restrictions.eq("wfAssignedUser", ApplicationUtilities.getCurrentUser()));
		return getHibernateTemplate().findByCriteria(criteria);
	}
	
	public List getDocgeneraldetails(Long docId){
		logger.debug("inside method(getDocGeneralDetails): searching for document with docId: " + docId);
		
		List docGeneralList = null;
		Session session = getHibernateTemplate().getSessionFactory().openSession();
		try{
			String queryString ="select general.docLocId, general.docCompanyId from DocGeneralDetailsDTO as general " +
								"where general.docId = :docId";
			
			Query hqlQuery = session.createQuery(queryString);
			hqlQuery.setParameter("docId", docId);
			docGeneralList = hqlQuery.list();
			for (Object object : docGeneralList) {}
		}
		catch(Exception e){
			logger.debug(e.getMessage(),e);
			if(null == docGeneralList){
				docGeneralList = new ArrayList();
			}
		}
		finally{
			if(session.isOpen())
				session.close();
		}
		return docGeneralList;
	}
	
	public  void deleteSelectedWFId(String wfId) throws Exception
	{
		logger.debug("inside method(getWorkFlowList): deleting the workflowId: " + wfId);
		//getHibernateTemplate().delete();
	}


	public Boolean updateWfEvent(DocumentWorkflowDetailsDTO detailsDTO) throws Exception {
		logger.debug("inside method(updateWfEvent): updating for document with docId: " + detailsDTO.getDocId());
		detailsDTO.setWfEventStatus(WorkflowEventStatus.CLOSED);
		updateDocumentWFDetails(detailsDTO);
		return true;
	}

	private void updateDocumentWFDetails(DocumentWorkflowDetailsDTO detailsDTO) throws Exception {
		logger.debug("inside method(updateDocumentWFDetails: updating details for document with docId: " + detailsDTO.getDocId());
		getHibernateTemplate().update(detailsDTO);
	}

	public void loadWorkflowDetails(DocumentWorkflowDetailsDTO detailsDTO) throws Exception{
		logger.debug("inside method(loadWorkflowDetails): for document with workflowId:" + detailsDTO.getWfId());
		getHibernateTemplate().load(detailsDTO, detailsDTO.getWfId());
	}

	public void createWfRowForSubmit(DocumentWorkflowDetailsDTO detailsDTO) throws Exception{
		logger.debug("inside method(createWfRowForSubmit): for document with docId: " + detailsDTO.getDocId());
		DocumentWorkflowDetailsDTO newWfDTO= new DocumentWorkflowDetailsDTO();
		newWfDTO.setDocId(detailsDTO.getDocId());
		newWfDTO.setWfStatus(WorkflowStatus.PFA);
		newWfDTO.setWfEventStatus(WorkflowEventStatus.OPEN);
		newWfDTO.setWfAssignedUser("2");
		newWfDTO.setVersion(detailsDTO.getVersion());
		newWfDTO.setCreatedDate(detailsDTO.getCreatedDate());
		newWfDTO.setStrCreatedAuthor(detailsDTO.getStrCreatedAuthor());
		newWfDTO.setStrUpdatedAuthor(ApplicationUtilities.getCurrentUser());
		newWfDTO.setUpdatedDate(new Date());
		saveWfRow(newWfDTO);
	}

	public void createWfRowForReject(DocumentWorkflowDetailsDTO detailsDTO) throws Exception {
		logger.debug("inside method(createWfRowForReject): creating row for document with docId: " + detailsDTO.getDocId());
		DocumentWorkflowDetailsDTO newWfDTO= new DocumentWorkflowDetailsDTO();
		newWfDTO.setDocId(detailsDTO.getDocId());
		newWfDTO.setWfStatus(WorkflowStatus.PFRS);
		newWfDTO.setWfEventStatus(WorkflowEventStatus.OPEN);
		newWfDTO.setWfAssignedUser("1");
		newWfDTO.setVersion(detailsDTO.getVersion());
		newWfDTO.setCreatedDate(detailsDTO.getCreatedDate());
		newWfDTO.setStrCreatedAuthor(detailsDTO.getStrCreatedAuthor());
		newWfDTO.setStrUpdatedAuthor(ApplicationUtilities.getCurrentUser());
		newWfDTO.setUpdatedDate(new Date());
		saveWfRow(newWfDTO);
	}
	public Query getQuery(String strQuery) throws Exception{
		return getSession().createQuery(strQuery);
	}
	private void saveWfRow(DocumentWorkflowDetailsDTO detailsDTO) throws Exception {
		logger.debug("inside method(saveWfRow): saving for document with docId: " + detailsDTO.getDocId());
		getHibernateTemplate().save(detailsDTO);
	}
	
	public void updateWfRow(DocumentWorkflowDetailsDTO detailsDTO) throws Exception{
		logger.debug("inside method(updateWfRow): updating for document with docId: " + detailsDTO.getDocId());
		getHibernateTemplate().update(detailsDTO);
	}
	
	public List<BusinessUnitTypeDTO> loadAllBU() throws Exception {
		logger.debug("inside method(loadAllBu)");
		return getHibernateTemplate().loadAll(BusinessUnitTypeDTO.class);
	}
	
	public List<DepartmentDetailsDTO> loadAllDepts() throws Exception {
		logger.debug("inside method(loadAllDepts)");
		return getSession().createCriteria(DepartmentDetailsDTO.class).list();
	}
	
	public List<RoleDetailsDTO> loadAllRoles() throws Exception{
		logger.debug("inside method(loadAllRoles)");
		return getHibernateTemplate().loadAll(RoleDetailsDTO.class);
	}
	
	public List<UserDetailsDTO> loadAllUsers() throws Exception {
		logger.debug("inside method(loadAllUsers)");
		return getHibernateTemplate().loadAll(UserDetailsDTO.class);
	}
	
	public List<UserDetailsDTO> loadAllUsersByCriteria(DetachedCriteria detachedCriteria){
		logger.debug("inside method(loadAllUsersByCriteria)");
		
		List<UserDetailsDTO> usersList = null;
		try{
			usersList = getHibernateTemplate().findByCriteria(detachedCriteria); 
		}
		catch (Exception e) {
			logger.error(e.getMessage(),e);
			if(null == usersList)
				usersList = new ArrayList<UserDetailsDTO>();
		}
		return usersList;
	}
	
	public List<CompanyDetailsDTO> loadAllCompany() throws Exception {
		logger.debug("inside method(loadAllCompany)");
		return getHibernateTemplate().loadAll(CompanyDetailsDTO.class);
	}

	public List<DocumentLinkDTO> loadLinkedDocument(long docId) throws Exception {
		logger.debug("inside method(loadLinkedDocument): for document with docId: " + docId);
		
		DetachedCriteria criteria = DetachedCriteria.forClass(DocumentLinkDTO.class);
		criteria.add(Restrictions.eq("linkedDocId", docId));
		
		return getHibernateTemplate().findByCriteria(criteria);
	}
	public List<DocumentLinkDTO> loadLinkDocumentbyParent(long docId) throws Exception{
		logger.debug("inside method(loadLinkDocumentbyParent): for document with docId: " + docId);

		DetachedCriteria criteria = DetachedCriteria.forClass(DocumentLinkDTO.class);
		criteria.add(Restrictions.eq("parentDocId", docId));
		return getHibernateTemplate().findByCriteria(criteria);
	}
	
	public List<DocumentLinkDTO> loadLinkedDocument(long docId,DocLinkType docLinkType) throws Exception {
		logger.debug("inside method(loadLinkedDocument): for document with docId: " + docId + " and docLinkType: " + docLinkType);
		
		DetachedCriteria criteria = DetachedCriteria.forClass(DocumentLinkDTO.class);
		criteria.add(Restrictions.eq("linkedDocId", docId));
		criteria.add(Restrictions.eq("linkType", docLinkType));
		return getHibernateTemplate().findByCriteria(criteria);
	}
	
	public List<DocumentLinkDTO> loadLinkDocumentbyParent(long docId,DocLinkType docLinkType) throws Exception{
		logger.debug("inside method(loadLinkDocumentbyParent): for document with docId: " + docId + " and docLinkType: " + docLinkType);
		DetachedCriteria criteria = DetachedCriteria.forClass(DocumentLinkDTO.class);
		criteria.add(Restrictions.eq("parentDocId", docId));
		criteria.add(Restrictions.eq("linkType", docLinkType));
		return getHibernateTemplate().findByCriteria(criteria);
	}

	public void loadUserDetails(UserDetailsDTO detailsDTO) throws Exception {
		logger.debug("inside method(loadUserDetails): for user with userId: " + detailsDTO.getUsername());
		getHibernateTemplate().load(detailsDTO, detailsDTO.getUsername());
	}

	public void saveMetaDataValues(List<DocumentMetadataValueDTO> metadataValueList) throws Exception {
		getHibernateTemplate().saveOrUpdateAll(metadataValueList);
		
	}

	public List loadAllByCriteria(DetachedCriteria detachedCriteria) {
		return getHibernateTemplate().findByCriteria(detachedCriteria);
	}

	public boolean removeOldMappingList(List<UserActivityGroup> oldActivityMappingList) {
		logger.debug("inside method(removeOldMappingList)");
		boolean resultOfDelete = false;
		try{
			for(UserActivityGroup userGroup : oldActivityMappingList){
				getHibernateTemplate().delete(userGroup);
				resultOfDelete = true;
			}
		}
		catch (Exception e) {
			logger.error(e.getMessage(),e);
		}
		return resultOfDelete;
	}


	public boolean saveNewDefaultDeactivateMapping(UserActivityGroup userActivityGroup) {
		logger.debug("inside method(saveNewDefaultDeactivateMapping): for document with docId: " + userActivityGroup.getdocId());
		boolean resultOfSave = false;
		try{
			getHibernateTemplate().save(userActivityGroup);
			resultOfSave = true;
		}
		catch(Exception e){
			logger.error(e.getMessage(), e);
		}
		return resultOfSave;
	}

	public boolean saveActivityTrackDetails(DocumentTrackDetailsDTO documentTrackObject){
		logger.debug("inside method(saveActivityTrackDetails): for document with docId: " + documentTrackObject.getDocId());
		boolean resultOfSave = false;
		try{
			getHibernateTemplate().save(documentTrackObject);
			resultOfSave = true;
		}
		catch (Exception e) {
			logger.error(e.getMessage(),e);
		}
		return resultOfSave;
	}


	public int uploadLocationMasterData(List<LocationMasterDTO> locationMasterList) {
		int counter = 0;
		int commitCounter = 0;
		Session session = sessionFactory.openSession();
		if(session!=null){
			try {
				Transaction transaction = session.beginTransaction();
				for(LocationMasterDTO objToSave : locationMasterList){
					session.save(objToSave);
					counter++;
					if(counter==1000){
						counter=0;
						transaction.commit();
						transaction = session.beginTransaction();
						commitCounter+=1000;
					}
				}
				commitCounter+=counter; 
				transaction.commit();
			} 
			catch (Exception e) {
				logger.error(e.getMessage(),e);
			}
			finally{
				if(session.isOpen())
					session.close();
			}
		}
		
		return commitCounter;
	}
	
	public DocGeneralDetailsDTO loadDocumentForId(long docId) {
		return getHibernateTemplate().get(DocGeneralDetailsDTO.class, docId);
	}
	
	/*public List<DepartmentDetailsDTO> getDepartmentForLocation(int buId) throws Exception {
		DetachedCriteria
		// TODO Auto-generated method stub
		return null;
	}*/
}
